package com.zhijian.warehouse.manage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import com.zhijian.util.BeanUtil;
import com.zhijian.util.page.Page;
import com.zhijian.warehouse.manage.dao.StoreRecordMapper;
import com.zhijian.warehouse.manage.entity.dto.stock.StockActionDto;
import com.zhijian.warehouse.manage.entity.dto.stock.StockStorageDto;
import com.zhijian.warehouse.manage.entity.export.StoreInExport;
import com.zhijian.warehouse.manage.entity.po.StoreRecord;
import com.zhijian.warehouse.manage.entity.po.Warehouse;
import com.zhijian.warehouse.manage.entity.vo.request.StoreRecordProductSaveOrUpdateVo;
import com.zhijian.warehouse.manage.entity.vo.request.StoreRecordProductSearchVo;
import com.zhijian.warehouse.manage.entity.vo.request.StoreRecordSaveOrUpdateVo;
import com.zhijian.warehouse.manage.entity.vo.request.StoreRecordSearchVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreInProductDetail;
import com.zhijian.warehouse.manage.entity.vo.response.StoreRecordProductVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreRecordVo;
import com.zhijian.warehouse.manage.enums.CodingEnum;
import com.zhijian.warehouse.manage.enums.StockActionEnum;
import com.zhijian.warehouse.manage.enums.StoreEnum;
import com.zhijian.warehouse.manage.service.*;
import com.zhijian.warehouse.manage.util.AssertCommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库记录业务处理层
 *
 * @author auto
 * @version: 1.0
 * @date 2024-10-20 21:42:59
 */
@Slf4j
@Service
public class StoreRecordServiceImpl implements StoreRecordService {

    @Autowired
    private StoreRecordMapper mapper;

    @Autowired
    private StoreRecordProductService storeRecordProductService;

    @Autowired
    private StoreService storeService;

    @Autowired
    private StoreLockService storeLockService;

    @Autowired
    private WarehouseService warehouseService;

    @Override
    public StoreRecord selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public StoreRecordVo selectVoById(Long id) {
        StoreRecordVo storeRecordVo = mapper.selectVoById(id);
        if (Objects.isNull(storeRecordVo)) {
            return null;
        }
        //产品
        storeRecordVo.setStoreRecordProductList(storeRecordProductService.selectList(StoreRecordProductSearchVo.builder()
                .storeRecordId(id)
                .build()));
        return storeRecordVo;
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public void deleteByIdList(List<Long> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return;
        }
        mapper.deleteByIdList(idList);
    }

    @Override
    public Long insert(StoreRecord storeRecord) {
        Date now = new Date();
        storeRecord.setCreateTime(now);
        storeRecord.setUpdateTime(now);
        return mapper.insert(storeRecord) > 0 ? storeRecord.getId() : 0L;
    }

    @Override
    public Long insertSelective(StoreRecord storeRecord) {
        Date now = new Date();
        storeRecord.setCreateTime(now);
        storeRecord.setUpdateTime(now);
        return mapper.insertSelective(storeRecord) > 0 ? storeRecord.getId() : 0L;
    }

    @Override
    public boolean update(StoreRecord storeRecord) {
        Date now = new Date();
        if (BeanUtil.isEmpty(storeRecord.getCreateTime()))
            storeRecord.setCreateTime(now);
        storeRecord.setUpdateTime(now);
        return mapper.updateByPrimaryKey(storeRecord) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(StoreRecord record) {
        Date now = new Date();
        record.setUpdateTime(now);
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(StoreRecordSaveOrUpdateVo saveOrUpdateVo) {
        if (BeanUtil.isNotEmpty(saveOrUpdateVo.getId()))
            return this.modify(saveOrUpdateVo);
        StoreRecord storeRecord = new StoreRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, storeRecord);
        storeRecord.setNumber(createNextNumber());
        storeRecord.setStatus(storeRecord.getStatus() == null ? StoreEnum.StatusEnum.DRAFT.getCode().byteValue() : storeRecord.getStatus());
        //先保存入库单
        Long storeRecordId = this.insertSelective(storeRecord);
        saveOrUpdateVo.setId(storeRecordId);
        //产品信息
        List<StoreRecordProductSaveOrUpdateVo> storeRecordProductList = saveOrUpdateVo.getStoreRecordProductList();
        if (BeanUtil.isNotEmpty(storeRecordProductList))
            for (StoreRecordProductSaveOrUpdateVo storeRecordProductSaveOrUpdateVo : storeRecordProductList) {
                //循环保存
                storeRecordProductSaveOrUpdateVo.setStoreRecordId(storeRecordId);
                storeRecordProductService.save(storeRecordProductSaveOrUpdateVo);
            }
        return storeRecordId != 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modify(StoreRecordSaveOrUpdateVo saveOrUpdateVo) {
        Long id = saveOrUpdateVo.getId();
        if (BeanUtil.isEmpty(id)) {
            this.save(saveOrUpdateVo);
            id = saveOrUpdateVo.getId();
        }
        StoreRecord old = this.selectById(id);
        AssertCommonUtil.check(BeanUtil.isEmpty(old), "此数据不存在或者已被删除");
        AssertCommonUtil.check(old.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue(), "当前出库单已审核通过，不能修改");
        old.setPlanCount(saveOrUpdateVo.getPlanCount());
        old.setRealCount(saveOrUpdateVo.getRealCount());
        old.setWarehouseId(saveOrUpdateVo.getWarehouseId());
        old.setNote(saveOrUpdateVo.getNote());
        old.setUpdateUserId(saveOrUpdateVo.getUpdateUserId());
        old.setUpdateUserName(saveOrUpdateVo.getUpdateUserName());
        this.update(old);
        storeRecordProductService.deleteByCondition(StoreRecordProductSearchVo.builder()
                .storeRecordId(id)
                .build());
        //产品信息
        List<StoreRecordProductSaveOrUpdateVo> storeRecordProductList = saveOrUpdateVo.getStoreRecordProductList();
        if (BeanUtil.isNotEmpty(storeRecordProductList))
            for (StoreRecordProductSaveOrUpdateVo storeRecordProductSaveOrUpdateVo : storeRecordProductList) {
                //循环保存
                storeRecordProductSaveOrUpdateVo.setStoreRecordId(id);
                storeRecordProductService.save(storeRecordProductSaveOrUpdateVo);
            }
        return true;
    }

    @Override
    public StoreRecordVo selectOne(StoreRecordSearchVo storeRecordSearchVo) {
        return mapper.selectOne(storeRecordSearchVo);
    }

    @Override
    public Integer count(StoreRecordSearchVo storeRecordSearchVo) {
        setAppStatusList(storeRecordSearchVo);
        return mapper.count(storeRecordSearchVo);
    }

    @Override
    public List<StoreRecordVo> selectList(StoreRecordSearchVo storeRecordSearchVo) {
        setAppStatusList(storeRecordSearchVo);
        return mapper.selectList(storeRecordSearchVo);
    }

    @Override
    public List<StoreInExport> selectStoreInExportList(StoreRecordSearchVo param) {
        setAppStatusList(param);
        return mapper.selectStoreInExportList(param);
    }

    private void setAppStatusList(StoreRecordSearchVo storeRecordSearchVo) {
        List<Byte> list = new ArrayList<>();
        if (storeRecordSearchVo.getAppStatus() != null) {
            if (storeRecordSearchVo.getAppStatus() == 0) {
                list = Arrays.asList(
                        StoreEnum.StatusEnum.END.getCode().byteValue(),
                        StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue()
                );
            } else if (storeRecordSearchVo.getAppStatus() == 1) {
                list = Collections.singletonList(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue());
            } else if (storeRecordSearchVo.getAppStatus() == 2) {
                list = Collections.singletonList(StoreEnum.StatusEnum.END.getCode().byteValue());
            }
        }
        storeRecordSearchVo.setAppStatusList(list);
    }

    @Override
    public Page<StoreRecordVo> selectPage(StoreRecordSearchVo storeRecordSearchVo) {
        AssertCommonUtil.check(Objects.isNull(storeRecordSearchVo.getPageNum()) || Objects.isNull(storeRecordSearchVo.getPageSize()), "分页参数不能为空");
        //先直接查总数
        int count = count(storeRecordSearchVo);
        //分页
        Page<StoreRecordVo> page = new Page<>(true, count, storeRecordSearchVo.getPageNum(), storeRecordSearchVo.getPageSize());
        storeRecordSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<StoreRecordVo> responseVos = this.selectList(storeRecordSearchVo);
        responseVos.forEach(storeRecordVo -> {
            // 拼接字段
            StringBuilder concatenatedFields = new StringBuilder();
            if (BeanUtil.isNotEmpty(storeRecordVo.getProductDetailList())) {
                storeRecordVo.getProductDetailList().forEach(storeInProductDetail -> {
                    concatenatedFields.append(storeInProductDetail.getProductNumber()).append("-");
                    concatenatedFields.append(storeInProductDetail.getProductName()).append("-");
                    concatenatedFields.append(storeInProductDetail.getProductModel()).append("-");
                    concatenatedFields.append(storeInProductDetail.getStoreCount()).append(";").append(System.lineSeparator());
                });
                storeRecordVo.setProductDetail(concatenatedFields.toString());
                //获取仓库名称并去重后以都逗号分隔
                List<String> warehouseNames = storeRecordVo.getProductDetailList().stream().map(StoreInProductDetail::getWarehouseName).distinct().collect(Collectors.toList());
                storeRecordVo.setWarehouseName(String.join(",", warehouseNames));
                storeRecordVo.setProductDetailList(null);
            }
        });
        page.setData(responseVos);
        return page;
    }

    @Override
    public boolean insertBatch(List<StoreRecord> entities) {
        return CollectionUtil.isNotEmpty(entities) && mapper.insertBatch(entities) > 0;
    }


    @Override
    public String selectMaxNumber() {
        return mapper.selectMaxNumberByDay(DateUtil.formatDate(new Date()));
    }

    @Override
    public String createNextNumber() {
        String maxCode = this.selectMaxNumber();
        if (StringUtils.isBlank(maxCode)) {
            return String.format("%s-%s-001", CodingEnum.PREFIX.RK.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")));
        }
        String[] maxCodeArray = maxCode.split("-");
        Integer i = Integer.valueOf(maxCodeArray[maxCodeArray.length - 1]);
        i++;
        return String.format("%s-%s-%s", CodingEnum.PREFIX.RK.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")), String.format("%03d", i));
    }


    @Override
    @Transactional
    public boolean submitAudit(StoreRecordSaveOrUpdateVo param) {
        List<StoreRecordProductSaveOrUpdateVo> storeRecordProductList = param.getStoreRecordProductList();
        //Long id = param.getId();
        modify(param);
        StoreRecord storeRecord = this.selectById(param.getId());
        AssertCommonUtil.check(Objects.equals(StoreEnum.StatusEnum.END.getCode().byteValue(), storeRecord.getStatus()), "入库单已完成审核，无法提交审核");
        AssertCommonUtil.check(BeanUtil.isEmpty(storeRecordProductList), "入库单无产品信息");
        storeRecordProductList.forEach(vo -> {
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseLocationId()), "产品明细中库位信息不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getStoreCount()), "产品明细中数量不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseId()), "产品明细中仓库不得为空");
        });
        //更新审核状态
        updateByPrimaryKeySelective(StoreRecord.builder().id(param.getId())
                .status(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue())
                .updateUserId(param.getUpdateUserId())
                .updateTime(new Date())
                .build());
        return true;
    }

    @Override
    @Transactional
    public boolean audit(StoreRecordSearchVo param, Integer sourceType) {
        StoreRecord storeRecord = selectById(param.getId());
        AssertCommonUtil.check(BeanUtil.isEmpty(storeRecord), "入库单不存在");

        AssertCommonUtil.check(storeRecord.getStatus().intValue() != StoreEnum.StatusEnum.WAIT_APPROVE.getCode(), "非待审核状态，无法审核");
        //审核通过
        if (param.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue()) {
            StoreRecordVo storeRecordVo = selectVoById(param.getId());
            AssertCommonUtil.check(BeanUtil.isEmpty(storeRecordVo) || BeanUtil.isEmpty(storeRecordVo.getStoreRecordProductList()), "入库单不存在或无产品信息");
            List<StockStorageDto> stockStorages = new ArrayList<>();
            List<StoreRecordProductVo> dets = storeRecordVo.getStoreRecordProductList();
            dets.forEach(p -> {
                if (storeLockService.selectLock(p.getWarehouseId())) {
                    Warehouse warehouse = warehouseService.selectById(p.getWarehouseId());
                    AssertCommonUtil.check(true, String.format("仓库%s已被锁定，请稍后再试", warehouse.getName()));
                }
                stockStorages.add(StockStorageDto.builder().productId(p.getProductId())
                        .warehouseLocationId(p.getWarehouseLocationId())
                        .warehouseId(p.getWarehouseId())
                        .count(p.getStoreCount())
                        .build());
            });
            StockActionDto action = StockActionDto.builder()
                    .actionType(StockActionEnum.ACTION_TYPE.STOCK_IN)
                    .stockStorages(stockStorages).voucherCode(storeRecordVo.getNumber())
                    .optId(storeRecordVo.getId())
                    .optSource(sourceType)
                    .voucherTime(com.zhijian.util.DateUtil.getTime(com.zhijian.util.DateUtil.DATE_FORMAT))
                    .optUserId(param.getUpdateUserId())
                    .crtUserId(storeRecordVo.getCreateUserId())
                    .build();
            storeService.stockAction(action);
        }
        //修改
        updateByPrimaryKeySelective(StoreRecord.builder().id(param.getId())
                .status(param.getStatus())
                .rejectMsg(param.getRejectMsg())
                .updateUserId(param.getUpdateUserId())
                .updateTime(new Date())
                .build());
        return true;
    }
}
